/*
 * Created on Feb 9, 2009
 *
 * TODO
 */
package jacky.lanlan.song.extension.vraptor2;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.vraptor.*;
import org.vraptor.component.LogicMethod;
import org.vraptor.http.VRaptorServletResponse;
import org.vraptor.view.ViewException;

/**
 * 
 * 实现 {@code Json} 的功能。需要依赖 ComponentLookupInterceptor 和 SettingAndValidationInterceptor
 * <p>
 * <i>不需要直接用这个拦截器，请使用 {@code EnhanceInterceptor}</i>
 * 
 * @author Jacky.Song
 */
public class JsonIntercepter extends BaseInterceptor {

	private static final ConcurrentMap<Class<? extends JsonEncoder>, JsonEncoder> ENCODER_CACHE = new ConcurrentHashMap<Class<? extends JsonEncoder>, JsonEncoder>();

	private JsonEncoder cacheAndReturnEncoder(Json anno) throws Exception {
		Class<? extends JsonEncoder> encoderClass = anno.encoder();
		JsonEncoder encoder = ENCODER_CACHE.putIfAbsent(encoderClass, encoderClass.newInstance());
		return encoder == null ? ENCODER_CACHE.get(encoderClass) : encoder;
	}

	@Override
	protected boolean canIntercept(LogicMethod logic) {
		return logic.getMetadata().isAnnotationPresent(Json.class);
	}

	@Override
	protected void doIntercept(LogicFlow flow) throws LogicException, ViewException {
		try {
			Json json = getLogicMethod(flow).getMetadata().getAnnotation(Json.class);
			VRaptorServletResponse resp = getResponse(flow);
			resp.setContentType(json.contentType());
			JsonEncoder encoder = this.cacheAndReturnEncoder(json);

			Object result = invokeLogicMethod(flow);
			// 直接输出结果到响应，实现 @Json 语义
			writeAndClose(encoder.encode(result).getBytes(json.encoding()), resp.getOutputStream());
		}
		catch (Exception e) {
			throw new LogicException("Json编码输出时出错： " + e);
		}
	}

}
